package logic

import (
	"context"
	"fmt"
	"log"
	"shop-manager/internal/do"
	"shop-manager/internal/repos/category"
	"shop-manager/internal/repos/goods"
	"shop-manager/internal/vo"
	"shop-manager/utils"

	"github.com/samber/lo"
)

//go:generate newc
type GoodsLogic struct {
	goodsRepo    *goods.GoodsRepo
	categoryRepo *category.CategoryRepo
}

func (l *GoodsLogic) ListGoods(ctx context.Context, req vo.ListGoodsReq) (rsp *vo.ListGoodsRsp, err error) {
	listData, total, err := l.goodsRepo.ListGoods(ctx, goods.ListGoodsParam{
		Page:     req.Page,
		PageSize: req.PageSize,

		Search:   req.Search,
		BarCodes: utils.SplitString(req.BarCode, ",;"),

		ClassID: req.ClassID,
		LevelID: req.LevelID,
		BrandID: req.BrandID,

		Sorts:             req.Sorts,
		OnlyUncategorized: req.OnlyUncategorized,

		IDs: req.IDs,
	})
	if err != nil {
		return nil, err
	}
	rsp = &vo.ListGoodsRsp{
		Items: make([]*vo.Goods, 0, len(listData)),
		Total: total,
	}

	categoryMap, err := l.categoryRepo.GetCategoryMap(ctx, category.ListCategoryParam{
		PageSize: do.PageSizeNoLimit,
		IDs: lo.Map(listData, func(item *do.Goods, index int) int {
			return item.CategoryID
		}),
		ReturnExtraFields: true,
	})
	if err != nil {
		return nil, err
	}

	for _, goods := range listData {
		category := categoryMap[goods.CategoryID]
		if category == nil {
			category = &do.Category{
				ID: do.CategoryTobeDone,
			}
		}
		goods := &vo.Goods{
			ID: goods.ID,

			BarCode:      goods.BarCode,
			Name:         goods.Name,
			FactoryPrice: goods.FactoryPrice,
			CategoryID:   goods.CategoryID,
			BoxRule:      goods.BoxRule,

			CreatedAt: goods.CreatedAt,
			UpdatedAt: goods.UpdatedAt,

			Category: &vo.Category{
				ID: category.ID,
			},
		}

		if category != nil {
			goods.Category = &vo.Category{
				ID:        category.ID,
				ClassID:   category.ClassID,
				ClassName: category.ClassName,
				LevelID:   category.LevelID,
				LevelName: category.LevelName,
				BrandID:   category.BrandID,
				BrandName: category.BrandName,
			}
		}

		rsp.Items = append(rsp.Items, goods)
	}

	return rsp, nil
}

func (l *GoodsLogic) CreateGoods(ctx context.Context, req vo.CreateGoodsReq) (rsp *vo.CreateGoodsRsp, err error) {
	if err = l.checkCategoryID(ctx, req.CategoryID); err != nil {
		return nil, err
	}
	classId, levelId, brandId := req.CategoryID[0], req.CategoryID[1], req.CategoryID[2]
	// 查找到真正的category.ID
	cagetory, err := l.categoryRepo.GetCategoryByKey(ctx, classId, levelId, brandId)
	if err != nil {
		return nil, err
	}

	goodsId, err := l.goodsRepo.CreateGoods(ctx, &do.Goods{
		BarCode:      req.BarCode,
		BoxRule:      req.BoxRule,
		CategoryID:   cagetory.ID,
		FactoryPrice: req.FactoryPrice,
		Name:         req.Name,
	})
	if err != nil {
		return nil, err
	}

	return &vo.CreateGoodsRsp{
		ID: goodsId,
	}, nil
}

func (l *GoodsLogic) UpdateGoods(ctx context.Context, req vo.UpdateGoodsReq) (rsp *vo.UpdateGoodsRsp, err error) {
	if err = l.checkCategoryID(ctx, req.CategoryID); err != nil {
		return nil, err
	}
	classId, levelId, brandId := req.CategoryID[0], req.CategoryID[1], req.CategoryID[2]
	// 查找到真正的category.ID
	cagetory, err := l.categoryRepo.GetCategoryByKey(ctx, classId, levelId, brandId)
	if err != nil {
		return nil, err
	}
	err = l.goodsRepo.UpdateGoods(ctx, &do.Goods{
		ID:           req.ID,
		BarCode:      req.BarCode,
		BoxRule:      req.BoxRule,
		CategoryID:   cagetory.ID,
		FactoryPrice: req.FactoryPrice,
		Name:         req.Name,
	})
	if err != nil {
		return nil, err
	}

	return &vo.UpdateGoodsRsp{}, nil
}

func (l *GoodsLogic) checkCategoryID(ctx context.Context, categoryID []int) (err error) {
	// 检查 req.CategoryID
	if len(categoryID) != 3 {
		return fmt.Errorf("category_id length must be 3(class_id, level_id, brand_id)")
	}
	classId, levelId, brandId := categoryID[0], categoryID[1], categoryID[2]
	cmm, err := l.categoryRepo.GetCategoryMetaMap(ctx, category.ListCategoryMetaParam{
		CategoryTypes: []do.CategoryType{do.CategoryType_Class, do.CategoryType_Level, do.CategoryType_Brand},
		IDs:           []int{classId, levelId, brandId},
	})
	if err != nil {
		return err
	}

	if _, ok := cmm[classId]; !ok {
		return fmt.Errorf("分类不存在: %d", classId)
	}
	if _, ok := cmm[levelId]; !ok {
		return fmt.Errorf("等级不存在: %d", levelId)
	}
	if _, ok := cmm[brandId]; !ok {
		return fmt.Errorf("品牌不存在: %d", brandId)
	}

	return nil
}

// ImportGoods 批量导入商品
// 支持同时导入多个商品，自动判断是新增还是更新
// 返回导入成功和失败的数量统计
func (l *GoodsLogic) BatchUpdate(ctx context.Context, req vo.BatchUpdateReq) (*vo.BatchUpdateCategoryRsp, error) {
	rsp := &vo.BatchUpdateCategoryRsp{}

	// 检查商品ID列表是否为空
	if len(req.GoodsIDs) == 0 {
		return rsp, fmt.Errorf("商品ID列表不能为空")
	}

	// 检查分类ID是否有效
	if err := l.checkCategoryID(ctx, req.CategoryID); err != nil {
		return rsp, err
	}

	// 获取实际的category.ID
	classId, levelId, brandId := req.CategoryID[0], req.CategoryID[1], req.CategoryID[2]
	category, err := l.categoryRepo.GetCategoryByKey(ctx, classId, levelId, brandId)
	if err != nil {
		return rsp, fmt.Errorf("获取分类失败: %v", err)
	}
	if category == nil {
		return rsp, fmt.Errorf("分类不存在")
	}

	goodsMap, err := l.goodsRepo.GetGoodsMap(ctx, goods.ListGoodsParam{
		IDs: req.GoodsIDs,
	})
	if err != nil {
		return rsp, err
	}

	// 批量更新商品分类
	for _, goodsId := range req.GoodsIDs {
		goods, ok := goodsMap[goodsId]
		if !ok {
			log.Printf("商品不存在 goods_id: %d\n", goodsId)
			rsp.FailedCount++
			continue
		}
		goods.CategoryID = category.ID
		err := l.goodsRepo.UpdateGoods(ctx, goods)
		if err != nil {
			log.Printf("更新商品分类失败 goods_id: %d, error: %v\n", goodsId, err)
			rsp.FailedCount++
		} else {
			rsp.SuccessCount++
		}
	}

	return rsp, nil
}

func (l *GoodsLogic) ImportGoods(ctx context.Context, req vo.ImportGoodsReq) (*vo.ImportGoodsRsp, error) {
	rsp := &vo.ImportGoodsRsp{}

	reqBarCodes := lo.Map(req, func(item *vo.ImportGoodsItem, index int) string {
		return item.BarCode
	})

	// 获取第一个分类作为默认分类
	// 注意：在实际应用中，应该根据业务需求设置合适的默认分类
	goods, _, err := l.goodsRepo.ListGoods(ctx, goods.ListGoodsParam{
		Page:     1,
		PageSize: do.PageSizeNoLimit,
		BarCodes: reqBarCodes,
	})
	if err != nil {
		return nil, fmt.Errorf("获取默认分类失败: %v", err)
	}

	barCodeToGoods := lo.SliceToMap(goods, func(goods *do.Goods) (string, *do.Goods) {
		return goods.BarCode, goods
	})
	tobeUpdated := make([]*do.Goods, 0)

	tobeCreated := make([]*do.Goods, 0)
	for _, item := range req {
		// 检查必填字段
		if item.Name == "" {
			return nil, fmt.Errorf("商品名称不能为空:%v", utils.JSONString(item))
		}
		if err := do.CheckGoodsBarCode(item.BarCode); err != nil {
			return nil, fmt.Errorf("商品条码非法:%v", utils.JSONString(item))
		}
		if item.BoxRule <= 0 {
			return nil, fmt.Errorf("商品箱规非法:%v", utils.JSONString(item))
		}

		// 检查商品是否已存在
		existingGoods := barCodeToGoods[item.BarCode]
		if existingGoods != nil { // 已存在, 覆盖之
			rsp.ExistedCount++
			tobeUpdated = append(tobeUpdated, &do.Goods{
				ID:           existingGoods.ID, // 按id更新
				BarCode:      item.BarCode,
				Name:         item.Name,
				FactoryPrice: item.FactoryPrice,
				BoxRule:      item.BoxRule,
				CategoryID:   do.CategoryTobeDone,
			})
		} else {
			tobeCreated = append(tobeCreated, &do.Goods{
				BarCode:      item.BarCode,
				Name:         item.Name,
				FactoryPrice: item.FactoryPrice,
				BoxRule:      item.BoxRule,
				CategoryID:   do.CategoryTobeDone,
			})
		}
	}

	if len(tobeCreated) > 0 {
		err = l.goodsRepo.BatchCreateGoods(ctx, tobeCreated)
		if err != nil {
			rsp.FailedCount += len(tobeCreated)
			return rsp, fmt.Errorf("批量创建商品失败: %v", err)
		}
		rsp.SuccessCount += len(tobeCreated)
	}
	if len(tobeUpdated) > 0 {
		for _, tobeUpdate := range tobeUpdated {
			err = l.goodsRepo.UpdateGoods(ctx, tobeUpdate)
			if err != nil {
				rsp.FailedCount++
				return rsp, fmt.Errorf("更新商品失败: %v", err)
			}
			rsp.SuccessCount++
		}
	}

	return rsp, nil
}
